Skip to content

Conversation

@Einere
Copy link
Contributor

@Einere Einere commented Jan 16, 2026

Fixes #255

Summary

This PR adds a new toSorted function that provides an immutable alternative to the existing sort function. Unlike sort, which mutates the original array, toSorted returns a new sorted array without modifying the input.

Changes

New Function: toSorted

  • Location: src/toSorted.ts
  • Export: Added to src/index.ts
  • Signature: Identical to sort function (supports currying)
  • Behavior: Returns a new sorted array without mutating the original

Key Features

  1. Immutability: Original array/iterable is never modified
  2. Native Support: Automatically uses Array.prototype.toSorted when available (ES2023+)
  3. Fallback Implementation: Creates a copy and sorts when native method is unavailable
  4. Full Compatibility: Supports arrays, Iterable, and AsyncIterable
  5. Pipeline Support: Works seamlessly with pipe and other FxTS functions

Implementation Details

  • Uses runtime detection to check for native Array.prototype.toSorted
  • Falls back to Array.from() + sort() when native method is unavailable
  • Maintains the same type signatures as sort for consistency
  • Uses @ts-expect-error comments to handle TypeScript type limitations (see TypeScript Version Considerations below)

Testing

Comprehensive test suite added in test/toSorted.spec.ts:

  • ✅ Basic sorting functionality (empty arrays, single elements, duplicates)
  • ✅ Immutability verification (original array unchanged)
  • ✅ Comparison with sort function (same results, no mutation)
  • ✅ Pipeline integration tests (pipe, filter, map combinations)
  • ✅ Sync and async test cases
  • ✅ Edge cases (strings, various iterable types)

All tests pass: npm test

TypeScript Version Considerations

Current Implementation

The current implementation uses @ts-expect-error comments to work around TypeScript type limitations:

  • Issue: Array.prototype.toSorted is not in TypeScript lib types until TS 5.2+
  • Current TS Version: 5.1.6 (as specified in package.json)
  • Current lib: ["es2020"] (as specified in tsconfig.json)

Why @ts-expect-error Instead of any?

We chose @ts-expect-error over any type assertions because:

  • ✅ More explicit about the intentional type bypass
  • ✅ Will fail compilation when types become available (TS 5.2+), alerting us to remove the workaround
  • ✅ Better documentation of the limitation
  • ✅ Maintains type safety for the rest of the code

Future Improvement Opportunity

When the project upgrades to TypeScript 5.2+ and updates tsconfig.json to include ES2023 in the lib array, we can:

  1. Remove all @ts-expect-error comments - TypeScript will recognize Array.prototype.toSorted natively
  2. Simplify the implementation - Direct type checking will be available
  3. Improve type safety - Better type inference for the native method

Recommended upgrade path:

// package.json
"typescript": "^5.2.0"  // or later

// tsconfig.json
"lib": ["es2020", "es2023"]  // or ["es2023"] if dropping ES2020 support

After upgrading, the code can be simplified to:

if (isArray(iterable)) {
  // TypeScript will recognize toSorted natively
  if (typeof Array.prototype.toSorted === "function") {
    return iterable.toSorted(f);  // No @ts-expect-error needed
  }
  // ... fallback
}

This is a non-breaking change - the current implementation works correctly and will continue to work after the upgrade, but the upgrade will allow us to remove the workarounds.

Code Quality

  • ✅ Passes npm run compile:check (TypeScript type checking)
  • ✅ Passes npm run lint (ESLint)
  • ✅ Passes npm run prettier (code formatting)
  • ✅ Follows existing code style and patterns
  • ✅ Matches sort function structure for consistency

Examples

import { filter, pipe, toSorted } from "@fxts/core";

// Basic usage
const arr = [3, 4, 1, 2, 5, 2];
const sorted = toSorted((a, b) => a > b, arr);
// sorted: [1, 2, 2, 3, 4, 5]
// arr: [3, 4, 1, 2, 5, 2] (unchanged)

// In a pipeline
const result = pipe(
  [3, 4, 1, 2, 5, 2],
  filter((a) => a % 2 !== 0),
  toSorted((a, b) => a > b),
);
// result: [1, 3, 5]

// With strings
toSorted((a, b) => a.localeCompare(b), "bcdaef");
// ["a", "b", "c", "d", "e", "f"]

Breaking Changes

None. This is a purely additive change.

Related

ES 기본 스펙에 toSorted 가 지원됨에 따라, fxts 에도 원본 배열을 수정하지 않는 toSorted 를 지원.
최대한 any 단언을 자제하도록 수정.
프리티어 무시 코드 제거
@Einere Einere requested a review from ppeeou as a code owner January 16, 2026 07:34
@Einere Einere marked this pull request as draft January 16, 2026 07:34
@Einere Einere mentioned this pull request Jan 16, 2026
@hg-pyun
Copy link
Collaborator

hg-pyun commented Jan 25, 2026

@Einere Is it ready? if you want to review, please change draft state.

@Einere Einere marked this pull request as ready for review January 25, 2026 12:25
@Einere
Copy link
Contributor Author

Einere commented Jan 25, 2026

@Einere Is it ready? if you want to review, please change draft state.

I have changed the PR to Ready for Review. 🤗

@ppeeou ppeeou changed the base branch from main to feat/toSorted February 1, 2026 10:33
@ppeeou
Copy link
Member

ppeeou commented Feb 1, 2026

@Einere Thank you for your contribution ✨

@ppeeou ppeeou merged commit bade6b8 into marpple:feat/toSorted Feb 1, 2026
1 check passed
@Einere Einere deleted the feat/support-to-sorted branch February 1, 2026 10:35
ppeeou added a commit that referenced this pull request Feb 1, 2026
* feat: Add immutable `toSorted` function (#379)

* feat: support toSorted with immutability

ES 기본 스펙에 toSorted 가 지원됨에 따라, fxts 에도 원본 배열을 수정하지 않는 toSorted 를 지원.

* chore: use any assertion as little as possible

최대한 any 단언을 자제하도록 수정.

* chore: remove prettier suppression

프리티어 무시 코드 제거

* chore: apply arrow function

* test: add type test

* docs: add toSorted

---------

Co-authored-by: HyungJun Choi <kjwsx23@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: immutable sort

3 participants